package com.zcsy.commons.util;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
import java.awt.image.Kernel;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

/**
 * @Title: BarcodeFactory.java
 * @Package： com.zcsy.commons.util
 * @Description: 二维码生成工具类
 *               <p>
 *               利用ZXING生成二维码图片
 *               </p>
 *
 * @author tanghan barbadosliy@163.com
 * @Copyright: 2015 武汉中财数元信息技术有限公司 All rights reserved.
 * @date 2015年9月18日
 * @version 1.0
 * @see JDK1.7.0_75
 * @since
 */

public class BarcodeFactory {
	// 图片宽度的一般
	private static final int IMAGE_WIDTH = 80;
	private static final int IMAGE_HEIGHT = 80;
	private static final int IMAGE_HALF_WIDTH = IMAGE_WIDTH / 2;
	private static final int FRAME_WIDTH = 2;

	private static final int BLACK = 0xFF000000; 
	private static final int WHITE = 0xFFFFFFFF;
	// 二维码写码器
	private static MultiFormatWriter mutiWriter = new MultiFormatWriter();

	public static void encode(String content, int width, int height,
			String srcImagePath, String destImagePath) {
		try {
			ImageIO.write(genBarcode(content, width, height, srcImagePath),
					"jpg", new File(destImagePath));
		} catch (IOException e) {
			e.printStackTrace();
		} catch (WriterException e) {
			e.printStackTrace();
		}
	}

	private static BufferedImage genBarcode(String content, int width,
			int height, String srcImagePath) throws WriterException,
			IOException {
		// 读取源图像
		BufferedImage scaleImage = scale(srcImagePath, IMAGE_WIDTH,
				IMAGE_HEIGHT, true);
		int[][] srcPixels = new int[IMAGE_WIDTH][IMAGE_HEIGHT];
		for (int i = 0; i < scaleImage.getWidth(); i++) {
			for (int j = 0; j < scaleImage.getHeight(); j++) {
				srcPixels[i][j] = scaleImage.getRGB(i, j);
			}
		}

		Map<EncodeHintType, Object> hint = new HashMap<EncodeHintType, Object>();
		hint.put(EncodeHintType.CHARACTER_SET, "utf-8");
		hint.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
		// 生成二维码
		BitMatrix matrix = mutiWriter.encode(content, BarcodeFormat.QR_CODE,
				width, height, hint);

		// 二维矩阵转为一维像素数组
		int halfW = matrix.getWidth() / 2;
		int halfH = matrix.getHeight() / 2;
		int[] pixels = new int[width * height];

		for (int y = 0; y < matrix.getHeight(); y++) {
			for (int x = 0; x < matrix.getWidth(); x++) {
				// 读取图片
				if (x > halfW - IMAGE_HALF_WIDTH
						&& x < halfW + IMAGE_HALF_WIDTH
						&& y > halfH - IMAGE_HALF_WIDTH
						&& y < halfH + IMAGE_HALF_WIDTH) {
					pixels[y * width + x] = srcPixels[x - halfW
							+ IMAGE_HALF_WIDTH][y - halfH + IMAGE_HALF_WIDTH];
				} 
				// 在图片四周形成边框
				else if ((x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH
						&& x < halfW - IMAGE_HALF_WIDTH + FRAME_WIDTH
						&& y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
						+ IMAGE_HALF_WIDTH + FRAME_WIDTH)
						|| (x > halfW + IMAGE_HALF_WIDTH - FRAME_WIDTH
								&& x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
								&& y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
								+ IMAGE_HALF_WIDTH + FRAME_WIDTH)
						|| (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH
								&& x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
								&& y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
								- IMAGE_HALF_WIDTH + FRAME_WIDTH)
						|| (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH
								&& x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH
								&& y > halfH + IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH
								+ IMAGE_HALF_WIDTH + FRAME_WIDTH)) {
					pixels[y * width + x] = 0xfDCDCDC;
				} else {
					// 此处可以修改二维码的颜色，可以分别制定二维码和背景的颜色；
					pixels[y * width + x] = matrix.get(x, y) ? 0xff000000
							: 0xfffffff;
				}
			}
		}

		BufferedImage image = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_RGB);
		image.getRaster().setDataElements(0, 0, width, height, pixels);

		return image;
	}

	/**
	 * 把传入的原始图像按高度和宽度进行缩放，生成符合要求的图标
	 * 
	 * @param srcImageFile
	 *            源文件地址
	 * @param height
	 *            目标高度
	 * @param width
	 *            目标宽度
	 * @param hasFiller
	 *            比例不对时是否需要补白：true为补白; false为不补白;
	 * @throws IOException
	 */
	private static BufferedImage scale(String srcImageFile, int newWidth,
			int width, boolean hasFiller) throws IOException {
		BufferedImage bufferedImage = null;
		try {
			File originalFile = new File(srcImageFile); 
			ImageIcon ii = new ImageIcon(originalFile.getCanonicalPath());
			Image i = ii.getImage();
			Image resizedImage = null;

			int iWidth = i.getWidth(null);
			int iHeight = i.getHeight(null);

			if (iWidth > iHeight) {
				resizedImage = i.getScaledInstance(newWidth, (newWidth * iHeight)
						/ iWidth, Image.SCALE_SMOOTH);
			} else {
				resizedImage = i.getScaledInstance((newWidth * iWidth) / iHeight,
						newWidth, Image.SCALE_SMOOTH);
			} 

			// This code ensures that all the pixels in the image are loaded.
			Image temp = new ImageIcon(resizedImage).getImage();

			// Create the buffered image.
			bufferedImage = new BufferedImage(temp.getWidth(null),
					temp.getHeight(null), BufferedImage.TYPE_INT_RGB);

			// Copy image to buffered image.
			Graphics g = bufferedImage.createGraphics();

			// Clear background and paint the image.
			g.setColor(Color.white);
			g.fillRect(0, 0, temp.getWidth(null), temp.getHeight(null));
			g.drawImage(temp, 0, 0, null);
			g.dispose();

			// Soften.
			float softenFactor = 0.0005f;
            float[] softenArray = { 0, softenFactor, 0, softenFactor,
                    1 - (softenFactor * 4), softenFactor, 0, softenFactor, 0 };
			Kernel kernel = new Kernel(3, 3, softenArray);
			ConvolveOp cOp = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
			bufferedImage = cOp.filter(bufferedImage, null);
			
		} catch (Exception e) { 
            e.printStackTrace(); 
        }
		return bufferedImage;
	}

	public static void zoom(BufferedImage srcBufferedImage, File destFile, String format, int destHeight, int destWidth) {
        try {
            int imgWidth = destWidth;
            int imgHeight = destHeight;
            int srcWidth = srcBufferedImage.getWidth();
            int srcHeight = srcBufferedImage.getHeight();
            double scaleW = destWidth * 1.0 / srcWidth;
            double scaleH = destHeight * 1.0 / srcHeight;
            if (scaleW >= scaleH) {
                double imgWidth1 = scaleH * srcWidth;
                double imgHeight1 = scaleH * srcHeight;
                imgWidth = (int)imgWidth1;
                imgHeight = (int)imgHeight1;
            } else {
                double imgWidth1 = scaleW * srcWidth;
                double imgHeight1 = scaleW * srcHeight;
                imgWidth = (int)imgWidth1;
                imgHeight = (int)imgHeight1;
            }
            BufferedImage destBufferedImage = new BufferedImage(destWidth, destHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D graphics2D = destBufferedImage.createGraphics();
            graphics2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1.0f)); 
            graphics2D.setBackground(Color.WHITE);
            graphics2D.clearRect(0, 0, destWidth, destHeight);
            graphics2D.drawImage(srcBufferedImage.getScaledInstance(imgWidth, imgHeight, Image.SCALE_SMOOTH), (destWidth / 2) - (imgWidth / 2), (destHeight / 2) - (imgHeight / 2), null);
            graphics2D.dispose();
            ImageIO.write(destBufferedImage, format, destFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
	
	public static BufferedImage toBufferedImage(BitMatrix matrix) { 
	     int width = matrix.getWidth(); 
	     int height = matrix.getHeight(); 
	     BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 
	     for (int x = 0; x < width; x++) { 
	       for (int y = 0; y < height; y++) { 
	         image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE); 
	       } 
	     } 
	     return image; 
	} 
	
	public static void writeToFile(BitMatrix matrix, String format, File file) 
		       throws IOException { 
	     BufferedImage image = toBufferedImage(matrix); 
	     if (!ImageIO.write(image, format, file)) { 
	       throw new IOException("Could not write an image of format " + format + " to " + file); 
	     } 
	}
	
	public static void writeToStream(BitMatrix matrix, String format, OutputStream stream) 
		       throws IOException { 
	     BufferedImage image = toBufferedImage(matrix); 
	     if (!ImageIO.write(image, format, stream)) { 
	       throw new IOException("Could not write an image of format " + format); 
	     } 
	}
	
	/**
	 * @Description 生成普通不带小图片的二维码
	 * @param text 内容
	 * @param width 宽
	 * @param height 高
	 * @param file 文件
	 * @author yuhaichao yhcjhun@foxmail.com
	 * @date 2015年11月6日
	 */
	public static void createCommonQRCode(String text, int width, int height, File file) {
		//二维码的图片格式 
        String format = "jpg"; 
        Hashtable hints = new Hashtable(); 
        //内容所使用编码 
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 
        try{
        	BitMatrix bitMatrix = new MultiFormatWriter().encode(text, 
        			BarcodeFormat.QR_CODE, width, height, hints);
        	MatrixToImageWriter.writeToFile(bitMatrix, format, file);
        } catch(Exception e) {
        	e.printStackTrace();
        }
	}
	
	public static void main(String[] args) {
//		BarcodeFactory.encode("http://www.baidu.com",
//						300, 300, "D:\\ding.jpg", "D:\\22.jpg");
//		try {
//            BufferedImage buffImg = ImageIO.read(new FileInputStream("D:\\ding.jpg"));
//            zoom(buffImg, new File("D:\\21.jpg"), "jpg", 80, 80);
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
	}
}